#include "BinaryCode.h"

namespace SimpleC
{
	namespace Compiler
	{
		wchar_t * OpCodeToString(OpCode opCode)
		{
			switch (opCode)
			{
			case OpCode::cPush:
				return L"cPush";
			case OpCode::iPush:
				return L"iPush";
			case OpCode::dPush:
				return L"dPush";
			case OpCode::sPush:
				return L"sPush";
			case OpCode::Pop:
				return L"Pop";
			case OpCode::sPop:
				return L"sPop";
			case OpCode::PushEmpty:
				return L"PushEmpty";
			case OpCode::sAdd:
				return L"sAdd";
			case OpCode::iAdd:
				return L"iAdd";
			case OpCode::iSub:
				return L"iSub";
			case OpCode::iMul:
				return L"iMul";
			case OpCode::iDiv:
				return L"iDiv";
			case OpCode::Mod:
				return L"Mod";
			case OpCode::dAdd:
				return L"dAdd";
			case OpCode::dSub:
				return L"dSub";
			case OpCode::dMul:
				return L"dMul";
			case OpCode::dDiv:
				return L"dDiv";
			case OpCode::And:
				return L"And";
			case OpCode::Or:
				return L"Or";
			case OpCode::Xor:
				return L"Xor";
			case OpCode::BitAnd:
				return L"BitAnd";
			case OpCode::BitOr:
				return L"BitOr";
			case OpCode::Not:
				return L"Not";
			case OpCode::iNeg:
				return L"iNeg";
			case OpCode::dNeg:
				return L"dNeg";
			case OpCode::Inc:
				return L"Inc";
			case OpCode::Dec:
				return L"Dec";
			case OpCode::Rsh:
				return L"Rsh";
			case OpCode::Lsh:
				return L"Lsh";
			case OpCode::iEql:
				return L"iEql";
			case OpCode::iNeq:
				return L"iNeq";
			case OpCode::iGeq:
				return L"iGeq";
			case OpCode::iLeq:
				return L"iLeq";
			case OpCode::iLess:
				return L"iLess";
			case OpCode::iGreater:
				return L"iGreater";
			case OpCode::dEql:
				return L"dEql";
			case OpCode::dNeq:
				return L"dNeq";
			case OpCode::dGeq:
				return L"dGeq";
			case OpCode::dLeq:
				return L"dLeq";
			case OpCode::dLess:
				return L"dLess";
			case OpCode::dGreater:
				return L"dGreater";
			case OpCode::i2d:
				return L"i2d";
			case OpCode::d2i:
				return L"d2i";
			case OpCode::c2s:
				return L"c2s";
			case OpCode::iLoad:
				return L"iLoad";
			case OpCode::dLoad:
				return L"dLoad";
			case OpCode::cLoad:
				return L"cLoad";
			case OpCode::sLoad:
				return L"sLoad";
			case OpCode::LoadOffset:
				return L"LoadOffset";
			case OpCode::sLoadOffset:
				return L"sLoadOffset";
			case OpCode::iStore:
				return L"iStore";
			case OpCode::dStore:
				return L"dStore";
			case OpCode::cStore:
				return L"cStore";
			case OpCode::sStore:
				return L"sStore";
			case OpCode::StoreOffset:
				return L"StoreOffset";
			case OpCode::sStoreOffset:
				return L"sStoreOffset";
			case OpCode::Jump:
				return L"Jump";
			case OpCode::JumpTrue:
				return L"JumpTrue";
			case OpCode::JumpFalse:
				return L"JumpFalse";
			case OpCode::Call:
				return L"Call";
			case OpCode::Ret:
				return L"Ret";
			/*case OpCode::SetRet:
				return L"SetRet";*/
			default:
				return L"unknown";
			}

		}
		void FunctionCode::Dump(TextWriter & writer)
		{
			writer<<L"Function "<<Name<<EndLine;
			int line = 0;
			for (auto & instr : Instructions)
			{
				writer<<String(line++)<<L"\t"<<OpCodeToString(instr.Operator)<<L"\t"<<String(instr.IntOperand)<<L"("<<String(instr.DoubleOperand)<<L")"<<EndLine;
			}
			writer<<L"End Function"<<EndLine;
		}
		void ProgramCode::Dump(const String & fileName)
		{
			StreamWriter writer(fileName);
			for (auto & func : Functions)
			{
				func->Dump(writer);
			}
		}
	}
}